#include "firework.h"

firework::firework()
{
    position = QVector3D(0.0f, 0.0f, 0.0f);
    interval = 4.0f;
    delay = 3 * static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
    timer = interval;
    stage = 0;
    sphere_loc.push_back(position);
    sphere_vel.push_back(QVector3D(0.0f + noise(1.0f), 0.0f + noise(1.0f), 15.0f + noise(0.5f)));
    sphere_col.push_back(QVector3D(1.0f, 1.0f, 1.0f)); // white

    expl_count = 200;
    r_life = 1.6f;
    p_life = 1.5f;
    color_type = int(3 * static_cast <float> (rand()) / static_cast <float> (RAND_MAX));

    sphere_life.push_back(r_life);
    sphere_life_ini.push_back(r_life);

    //tail = ParticleSystem(2500, 0.3f, 0.1f, 10000, position, rocket_rad / 4.0f, src_type::dim3, axis::Z, -1.0f, 20.0f, QVector3D(1.0f, 1.0f, 1.0f));
    //tail.set_collision(false);
}
firework::firework(QVector3D pos, float t, float rlife, float plife, int explc)
{ // customized firework
    position = pos;
    interval = t;
    delay = 3 * static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
    timer = interval;
    stage = 0;
    sphere_loc.push_back(position);
    sphere_vel.push_back(QVector3D(0.0f + noise(0.1f), 0.0f + noise(0.1f), 15.0f + noise(0.1f)));
    sphere_col.push_back(QVector3D(1.0f, 1.0f, 1.0f));

    expl_count = explc;
    r_life = rlife;
    p_life = plife;
    color_type = int(3 * static_cast <float> (rand()) / static_cast <float> (RAND_MAX));

    sphere_life.push_back(rlife);
    sphere_life_ini.push_back(r_life);

    //tail = ParticleSystem(2500, 0.3f, 0.1f, 10000, position, rocket_rad / 4.0f, src_type::dim3, axis::Z, -1.0f, 20.0f, QVector3D(1.0f, 1.0f, 1.0f));
    //tail.set_collision(false);
}
void firework::update(float dt) {

    if (delay > 0) delay -= dt;
    else {
        timer -= dt;
        for (int i = 0; i < sphere_loc.size(); i++) {
            sphere_loc[i] += (sphere_vel[i] * dt);
            float vel=sphere_vel[i].z();
            sphere_vel[i].setZ(vel+g*dt);
            sphere_life[i] -= dt;
        }

        // launch stage
        if (stage == 0) {
            //tail.set_src_pos(sphere_loc[0]); // the particle source follows the rocket
            if (sphere_life[0] <= 0) {
                explode();
            }
        }
        // explosion stage
        else {
            float damping_fac = 0.95f;
            vector<int> del_list;
            for (int i = sphere_loc.size() - 1; i >= 0; i--) {
                sphere_vel[i] *= damping_fac; // damping effect
                if (sphere_life[i] <= 0) del_list.push_back(i);
            }
            for (int i : del_list) { // delete the dead spheres
                del_sphere(i);
            }
        }
        //tail.update(dt, ParticleSystem::particle_type::others, QVector3D(0.0f, 0.0f, 0.0f), 0.0f);

        // restart
        if (timer <= 0) {
            timer = interval;
            stage = 0;
            g = -9.8f;
            sphere_loc.push_back(position);
            sphere_vel.push_back(QVector3D(0.0f + noise(0.1f), 0.0f + noise(0.1f), 15.0f + noise(0.1f)));
            sphere_col.push_back(QVector3D(1.0f, 1.0f, 1.0f));
            color_type = int(3 * static_cast <float> (rand()) / static_cast <float> (RAND_MAX));
            sphere_life.push_back(1.6f);
            sphere_life_ini.push_back(1.6f);

            // tail.set_gen(true);
            // tail.set_src_pos(sphere_loc[0]);
        }
    }

}
// explosion creates a number of smaller spheres
void firework::explode() {
    stage = 1; // switch to explosion stage
    g = -7.0f;
    //tail.set_gen(false); // stop emitting particle tail
    float explosion_speed = 9.0f;
    for (int i = 0; i < expl_count; i++) {
        //printf("%f %f %f\n", sphere_loc[0].x, sphere_loc[0].y, sphere_loc[0].z);
        sphere_loc.push_back(sphere_loc[0]);
        sphere_vel.push_back(explosion_speed * sample_vel());
        float life = p_life + noise(0.4f);
        sphere_life_ini.push_back(life);
        sphere_life.push_back(life);
    }
    generate_color();
    // delete the first sphere (the rocket)
    del_sphere(0);
}

// delete the sphere at index i
void firework::del_sphere(int i) {
    int last = sphere_loc.size() - 1;
    sphere_loc[i] = sphere_loc[last];
    sphere_loc.pop_back();
    sphere_vel[i] = sphere_vel[last];
    sphere_vel.pop_back();
    sphere_col[i] = sphere_col[last];
    sphere_col.pop_back();
    sphere_life[i] = sphere_life[last];
    sphere_life.pop_back();
    sphere_life_ini[i] = sphere_life_ini[last];
    sphere_life_ini.pop_back();
}

// generate random float in [-0.5, +0.5] * scale
float firework::noise(float scale) {
    return scale * static_cast <float> (rand()) / static_cast <float> (RAND_MAX) - 0.5;
}

// sample velocity on a sphere
QVector3D firework::sample_vel() {
    float theta = 2 * M_PI * static_cast <float> (rand()) / static_cast <float> (RAND_MAX);  // 0 - 2PI
    float phi = M_PI * static_cast <float> (rand()) / static_cast <float> (RAND_MAX); // 0 - PI
    float noise = 1 - (0.1f * static_cast <float> (rand()) / static_cast <float> (RAND_MAX)); // 0.9 - 1
    QVector3D tempVec3 = noise * QVector3D(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi));
    return tempVec3;
}

// sample color
void firework::generate_color() {
    QVector3D col0;
    QVector3D col1;
    switch (color_type) {
    case 0:
        col0 = QVector3D(1.0f, 0.0f, 0.0f); // red
        col1 = QVector3D(0.0f, 0.0f, 1.0f); // blue
        break;
    case 1:
        col0 = QVector3D(0.0f, 1.0f, 1.0f); // cyan
        col1 = QVector3D(1.0f, 1.0f, 0.0f); // yellow
        break;
    default:
        col0 = QVector3D(1.0f, 0.0f, 1.0f); // magenta
        col1 = QVector3D(0.0f, 1.0f, 0.0f); // green
    }
    for (int i = 0; i < expl_count; i++) {
        if (noise(1.0f) > 0) sphere_col.push_back(col0);
        else sphere_col.push_back(col1);
    }
}
